/**
  * @file       Fingervein.c
  * @brief      指静脉组件
  * @copyright  Copyright (c) 2020~2030 ShenZhen Dxtc Tech. Co., Ltd.
  * All rights reserved.
  * @version    V1.0
  * @author     Liangtao
  * @date       2022-06-21 14:52:09
  * @note       鼎新同创·智能锁
  *
  *****************************************************************************/

#include "component.h"
#include "device.h"
#include "fingervein.h"
#include "cycfg_peripherals.h"

#define FINGERVEIN_DEBUG

/* debug print interface */
#if defined(FINGERVEIN_DEBUG)
	#define FINGERVEIN_TASK_DEBUG_LOG(format, ...) OSAL_LOG(C_LIGHT_CYAN format C_NONE, ##__VA_ARGS__)
	#define __FINGERVEIN_TASK_DEBUG_LOG(format, ...) __OSAL_LOG(C_LIGHT_CYAN format C_NONE, ##__VA_ARGS__)
#else
	#define FINGERVEIN_TASK_DEBUG_LOG(format, ...)
	#define __FINGERVEIN_TASK_DEBUG_LOG(format, ...)
#endif

#define FINGERVEIN_TASK_LOG(format, ...) OSAL_LOG(C_LIGHT_CYAN format C_NONE, ##__VA_ARGS__)
#define __FINGERVEIN_TASK_LOG(format, ...) __OSAL_LOG(C_LIGHT_CYAN format C_NONE, ##__VA_ARGS__)

/* 定义虚拟硬件接口 */
#if defined(BOARD_M30J0_ADD_FINGERVEIN_WITH_FPT)
	#define VHW_PIN_FINGERVEIN_POWER 			vPIN_C28		//Fingervein-power,595控制，(K8603，指静脉与指纹共存)
#elif defined(BOARD_M30J0_ADD_FINGERVEIN_WITHOUT_FPT)
	#define VHW_PIN_FINGERVEIN_POWER 			vPIN_C27		//Fingervein-power,单独IO口控制，(901VP，指静脉代替指纹)
#endif
#define IRQ_VHW_FINGERVEIN                 	vPIN_I17
#define VHW_UART_FINGERVEIN 				vUART_7			


/* 指静脉事件*/
#define EVENT_FINGERVEIN_PROTOCOL          	(0X00000001)					//处理指静脉串口协议事件
#define EVENT_FINGERVEIN_PROCESS      		(0X00000002)	  				//指静脉录入和验证流程处理事件
#define EVENT_GET_TOUCH_STATUS 				(0X00000004)	  				//获取指静脉Touch状态事件
#define EVENT_CHECK_FINGER_STATUS 			(0X00000008)	  				//定时检测指静脉录入时手指是否正确放置事件
#define EVENT_ENROLL_GET_IMAGE_TIMER 		(0X00000010)	  				//指静脉单次录入时定时采图事件
#define EVENT_WAIT_FINGER_AWAY 				(0X00000020)	  				//指静脉单次录入时结束采图，等待手指移开事件
#define EVENT_SYNC_WITH_MODULE 				(0X00000040)	  				//指静脉上电后的同步握手事件


/* Fingervein power control */
#define FINGERVEIN_MODULE_POWER_ON  Device_Write(VHW_PIN_FINGERVEIN_POWER, NULL, 0, 1)
#define FINGERVEIN_MODULE_POWER_OFF Device_Write(VHW_PIN_FINGERVEIN_POWER, NULL, 0, 0)


#define FINGERVEIN_OPERATE_RINGBUFF_NUM 3	                        	/* 与指静脉模块握手命令环形缓存队列深度 */
#define FINGERVEIN_TX_RINGBUFF_NUM 10	                        		/* 发送命令环形缓存队列深度 */
#define FINGERVEIN_RX_RINGBUFF_NUM 500	                        		/* 接收命令环形缓存队列深度 */
#define FINGERVEIN_RX_RINGBUFF_SIZE 1	                        		/* 接收命令环形队列缓存单个消息大小 */
#define PROTOCOL_RESEND_TIMES          3								/* 指静脉指令超时重发次数 */


static RingBufferHandle_t fingerveinTx_rbHandle = NULL;    				/* 发送循环队列句柄 */
static RingBufferHandle_t fingerveinRx_rbHandle = NULL;		  			/* 指静脉串口接收数据的队列句柄 */
static RingBufferHandle_t operate_rbHandle = NULL;      			   /* 与指静脉模块握手操作循环队列句柄 */

#define SWAP16(n) ((((uint16_t)(n) >> 8) & 0x00FF) | (((uint16_t)(n) << 8) & 0xFF00))

/* 消息回调函数类型 */
typedef void (*FingerveinMessageCallback_fun_t)(uint8_t cmd, uint8_t result, uint8_t *data, uint8_t len);

/* 回调函数 */
static FingerveinMessageCallback_fun_t pCmdCallback = NULL;


//指静脉运行状态数据
typedef struct
{
    WorkMode_enum_t mode;                           //工作模式
    bool sensor_init_flag;                          //sensor初始化成功标志
    uint8_t enroll_num;                             //注册次数
	uint8_t finger_out_count;						//单次录入过程中手指不正确放置的次数；
} Fingervein_Status_Data_stu_t;

/* 指静脉组件状态类型 */
typedef enum 
{
	FVN_STATUS_INIT,			                        //初始状态
	FVN_STATUS_WAIT_ACK,								//等待模组ACK回复
	FVN_STATUS_ENROLL_GET_IMAGE_TIME_UP,				//自动注册单次采图定时器时间到
	FVN_STATUS_ENROLL_SUCCESS,						//指静脉录入成功
	FVN_STATUS_ENROLL_FAILED,							//指静脉录入失败
	FVN_STATUS_VERIFY_GET_IMAGE_OK,					//自动验证采图成功处理
	FVN_STATUS_VERIFY_SUCCESS,						//指静脉验证成功
	FVN_STATUS_VERIFY_FAILED,							//指静脉验证失败
	FVN_STATUS_FINGER_AWAY,							//手指已挪开
    FVN_STATUS_WAIT_FINGER_AWAY_START,                //开始等待手指挪开
    FVN_STATUS_END,                                   //结束状态
}FingerveinStatus_enum_t;


#define FINGERVEIN_PROCESSOR_TIME           				10		/* 指静脉detect时间处理时间 */
#define FINGERVEIN_ENROLL_GEI_IMAGE_TIME           		4000		/* 指静脉单次录入采图时长（单位：ms） */
#define FINGERVEIN_ENROLL_WAIT_FINGER_AWAY_TIME           4000		/* 指静脉采图完成后，定时检测手指是否拿开的时间间隔（单位：ms） */
#define AUTO_ENROLL_MAX_NUMS								6		/* 自动指令注册指静脉时候需要录入的次数 */
#define FINGERVEIN_ENROLL_WAIT_FINGER_AWAY_NUMS				3		/* 指静脉采图完成后，手指一直未拿开的的超时检测次数 */
#define FINGERVEIN_MODULE_BOOT_TIME							600		/* 指静脉模组启动等待时间（单位：ms） */


/* 指静脉中断唤醒系统 */ 
__NVRAM static uint8_t fingervein_wake_flag = 0;

/* 等待切换的指静脉模式 */
static WorkMode_enum_t fingerveinModeBuff = WORK_MODE_DISABLE;

/* 指静脉初始化标志 */
static FlagStatus fingervein_Init_Flag = RESET;

/* 指静脉处理流程启动标志 */
static FlagStatus process_Start_Flag = RESET;

/* 指静脉模组本身上电初始化握手成功标志，此时MCU已收到指静脉上报的0X55信号 */
static FlagStatus module_Ready_Flag = RESET;

/* 应用层下发的指静脉存储ID */
static uint8_t template_Save_Num = 0xEE;

/* 指静脉验证指令，模组搜索到模板编号 */
static uint8_t template_Verify_Num = 0xFF;

/* 指静脉运行状态数据 */
static Fingervein_Status_Data_stu_t fingervein_Status_Data;

/* 指静脉组件状态 */
static FingerveinStatus_enum_t fingervein_Status = FVN_STATUS_INIT;

/* 自动验证模式下，指静脉中断触发，开始获取TouchStatus，防止多次中断触发，重复查询，*/
static FlagStatus getTouchStatus_Start_Flag = RESET;

/* 自动验证模式下，单次指静脉中断有效时间内去获取指静脉touch状态的计数*/ 
static uint8_t getTouchStatus_Count = 0;

/* 指静脉注册流程中断标志 */ 
static FlagStatus enroll_Abort_Flag = RESET;

/* 指静脉注册单次采图前，手指已接触指静脉模块两端触点的标志 */
static FlagStatus finger_Touch_OK_Flag = RESET;

/* 录入采图定时器开启标志，如果用户在单次采图过程中未满足滑动时间提前松手时候辅助判断；*/
static FlagStatus Enroll_Get_Image_Timer_On_Flag = RESET;

/* 录入模式下，单次采图完成后，等待手指移开的计数，次数超时会退出录入流程*/ 
static uint8_t wait_Finger_Away_Count = 0;

/* 指静脉模块上电标志 */ 
static FlagStatus module_PowerOn_Flag = RESET;

/* Fingervein_Task首次上电标志 */ 
static FlagStatus fisrt_PowerOn_Flag = RESET;



/* 指静脉模块指令码 */ 
#define CMD_AUTO_ENROLL				0X31		//自动注册指令
#define CMD_AUTO_VERIFY				0X32		//自动验证指令
#define CMD_HELLO					0X35		//握手指令
#define CMD_DEL_TEMPLATE			0X0C		//删除模板指令
#define CMD_DEL_ALL_TEMPLATE		0X0D		//清空指静脉库指令
#define CMD_GET_TOUCH_STATUS  		0X54		//获取touch状态指令
#define CMD_ABORT  					0X30		//取消指令
#define CMD_GET_VERSION  			0X61		//获取模组软件版本号指令
#define CMD_ATE_TEST  			    0X50		//指静脉整机测试指令


/* 指静脉TouchStatus，0X54命令的返回值*/
#define NO_FINGER_TOUCH 			0X00		//无手指
#define ONLY_LEFT_TOUCH				0X01		//指尖接触指静脉的单端触点，为方便，定义为只接触左边
#define ONLY_RIGHT_TOUCH			0X02		//指末接触指静脉的单端触点，为方便，定义为只接触右边
#define TOUCH_SUCCESS				0X03		//手指同时接触指静脉的两端触点，为有效触发；

/* 指静脉模块ACK确认码  */
#define FINGERVEIN_RES_SUCCESS              0X00   //成功
#define FINGERVEIN_RES_FAILE                0X01   //失败
#define FINGERVEIN_RES_TIMEOUT              0X26   //自动注册，返回超时

#define TX_RES_TIMEOUT              0XFF   //MCU发送操作超时
#define TX_RES_OK            		 0XAA   //MCU发送正常，并已收到指静脉的回复包；

// 不同指令的超时时间
#define NORMAL_CMD_TIMEOUT 			1500							//一般指令超时时间(单位：ms)
#define HELLO_CMD_TIMEOUT 			500								//握手指令超时时间(单位：ms)
#define ENROLL_CMD_TIMEOUT 			40000							//指静脉注册指令超时时间(单位：ms)
#define VERIFY_CMD_TIMEOUT 			2500							//指静脉验证指令超时时间(单位：ms)
#define ATE_TEST_CMD_TIMEOUT 		12000							//指静脉整机测试指令超时时间(单位：ms)



/************************************【START】指静脉串口发送和接收数据结构体定义***************************************/
#define HELLO_OK				  0X55		  //指静脉模组的就绪握手信号，每次启动完成后上报；
#define PROTOCOL_STX              0xEF01      //帧数据头
#define CHIPADDR                  0xFFFFFFFF  //芯片地址

#define PACK_TYPE_CMD    		  0X01        //包类型：命令包，MCU --> Fingervein
#define PACK_TYPE_DATA            0X02	      //包类型：数据包，且有后续包，Fingervein --> MCU
#define PACK_TYPE_DATA_END        0X08	      //包类型：最后一个数据包，即结束包，Fingervein --> MCU
#define PACK_TYPE_ACK             0X07	      //包类型：应答包，Fingervein --> MCU

/*功能函数宏定义*/
#define CHECK_SUM_DATA_START      6           //计算校验和时，数据起始位相对数据帧首字节的偏移位数
#define CHECK_SUN_LEN_ADD         1	          //计算校验和时，计算长度相对帧数据长度增加的个数

//TODO
#define MAX_CMD_PACKAGE_LEN        64          		//指静脉指令包最大包长
#define MAX_TX_PACKAGE_LEN        550          		//指静脉发送最大包长（PS：指静脉OTA升级时，升级数据分包大小为512个字节）
#define MAX_RX_PACKAGE_LEN        128         		//指静脉接收最大包长

#define MAX_CMD_PARAM_LEN			20			//指静脉指令码的最大参数长度；

#pragma pack(1)

/* 锁发送命令给指静脉模组消息结构 */
typedef struct
{
	FingerveinMessageCallback_fun_t cb;
	uint8_t cmd;
	uint16_t dataLen;
	uint32_t timeout;
	uint8_t dataBuf[MAX_CMD_PACKAGE_LEN];
} FingerveinTxCmdMsg_stu_t;


/*帧头数据结构*/
typedef struct
{
	uint16_t stx;                               //帧头
	uint32_t chipAddr;                          //芯片地址
	uint8_t msgType;                            //帧标识
	uint16_t dataLen;                           //data数据长度
} ProtocolDataHead_stu_t;

/*帧数据结构*/
typedef struct
{
	ProtocolDataHead_stu_t head;                //帧头结构体
	uint8_t data[];				                      //命令
} CmdPacket_stu_t;

/*指静脉命令参数据结构*/
typedef struct
{
	uint8_t cmd;                					//指令码
	uint8_t param[];				                //指令参数，长度不定
} CmdParamPacket_stu_t;

#pragma pack()

//发送包信息
static struct
{
	uint8_t dataBuf[MAX_TX_PACKAGE_LEN];      		//当前发送的整包数据
	uint16_t dataLen;		                      	//当前发送数据的总长度

	uint8_t cmd;			                        //发送的命令
	uint8_t sendCnt;			                    //发送次数计数
	FlagStatus waitAckFlag;	                  		//等待ack标志位
	uint32_t timeStamp;		                    	//时间戳
	uint32_t waitAckTimeout;                  		//等待超时时间
	enum
	{					 
		TX_STA_IDLE,	  
		TX_STA_WAIT_ACK, 
    	TX_STA_WAIT_NEXT
	} status;
} CmdPacketTxInfo;

//接收包信息
static struct
{
	uint8_t protocolBuf[MAX_RX_PACKAGE_LEN]; 			//协议buff
	uint8_t protocolCount;				  		      	//协议计数

} CmdPacketRxInfo;
/************************************【END】指静脉串口发送和接收数据结构体定义**************************************/

/*********指静脉操作指令对应函数*********/
static void Fingervein_Cmd_Hello(void);										//指静脉握手指令：35H
static void Fingervein_Cmd_AutoEnroll(void);								//指静脉自动注册指令：31H
static void Fingervein_Cmd_AutoVerify(void);								//指静脉自动验证指令32H
static void Fingervein_Cmd_DelTemplate(uint8_t startNum, uint8_t nums);		//指静脉删除模板指令：0CH
static void Fingervein_Cmd_GetTouchStatus(void);							//指静脉获取touch状态指令：54H
static void Fingervein_Cmd_DelAllTemplate(void);							//指静脉清空指静脉库指令：0DH
static void Fingervein_Cmd_Abort(void);										//指静脉取消指令：30H
/********************************************/ 


#define FINGERVEIN_NV_SIZE 	sizeof(NvFingervein_stu_t)                                	 	/* 指静脉NV区域大小 */

/**
  * @brief 创建指静脉数据读取缓冲区队列
  *
  * @note 
  */
static void Fingervein_CreateRingBuffHandle(void)
{
	if (fingerveinTx_rbHandle == NULL)
	{
		fingerveinTx_rbHandle = OSAL_RingBufferCreate(FINGERVEIN_TX_RINGBUFF_NUM, sizeof(FingerveinTxCmdMsg_stu_t));
	}
	if (fingerveinRx_rbHandle == NULL)
	{
		fingerveinRx_rbHandle = OSAL_RingBufferCreate(FINGERVEIN_RX_RINGBUFF_NUM, FINGERVEIN_RX_RINGBUFF_SIZE);
	}
	if (operate_rbHandle == NULL)
	{
		operate_rbHandle = OSAL_RingBufferCreate(FINGERVEIN_OPERATE_RINGBUFF_NUM, sizeof(FingerveinTxCmdMsg_stu_t));
	}
}

/**
  * @brief   指静脉串口回调函数
  * @details 详细说明：
  *         
  * @param[in]  dev：
  * @param[in]  data：
  * @param[in]  len：
  * 
  * @return       NULL
  */
static void Fingervein_ReceiveCb(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
	if (fingerveinRx_rbHandle == NULL)
	{
		return;
	}
	for (uint32_t i = 0; i < len; i++)
	{
		uint8_t tmp = ((uint8_t *)data)[i];
		if (OSAL_RingBufferWrite(fingerveinRx_rbHandle, &tmp) != SUCCESS)
		{
			FINGERVEIN_TASK_LOG("Fingervein ringbuff write err\r\n");
			return;
		}
	}
}

/**
  * @brief  指静脉中断处理
  * @note   
  * @return 
  */
static void Fingervein_Int_Irq_Handler(char *name, uint8_t status, uint8_t times)
{
    if (status == INPUT_PORT_STA_PRESS && times != 0xFF)
    {
        /* 创建ISR事件 */
        OSAL_EventCreateFromISR(COMP_FINGERVEIN);
    }
}

/**
  * @brief  指静脉协议初始化
  *
  * @note
  */
static void Fingervein_ProtocolInit()
{
	CmdPacketTxInfo.status = TX_STA_IDLE;

}

/**
  * @brief 清除指静脉发送和设置缓存数据
  *
  * @note  
  */
static void Fingervein_ResetRingBuffData(void)
{
	OSAL_RingBufferReset(fingerveinTx_rbHandle);
	OSAL_RingBufferReset(fingerveinRx_rbHandle);
	OSAL_RingBufferReset(operate_rbHandle);
}

/**
  * @brief  计算校验和
  * @note
  *
  * @param  pData: 数据指针
  * @param  len: 数据长度
  * @return 数据校验和:

  */
static uint16_t Fingervein_CalcCheckSum(uint8_t *pData, uint16_t len)
{
	uint16_t sum = 0;
	for (; len; len--)
	{
		sum += *pData++;
	}
	return sum;
}


/**
  * @brief  从底层环形缓存获取一包数据并解析
  *
  * @note   底层驱动收到数据，会暂存在环形缓存区
  *
  * @return 返回解析后的数据包地址，解析失败返回NULL
  */
static uint8_t *Fingervein_GetOnePacket(void)
{
	static uint8_t getPacketTimeoutCnt = 0;
	uint8_t *protocolBuff = NULL;                               //临时指针，数据接收解析时，指向CmdPacketRxInfo的解析数据缓存
	uint8_t *pCnt = NULL;                                       //临时指针，数据接收解析时，指向CmdPacketRxInfo的解析计数
	uint16_t CalcSum = 0;										//实际计算的校验和
	uint16_t recvSum = 0;										//收到的数据帧中的校验和
	static uint16_t packetLen = 0;                              //整包长度
	uint8_t tmpData;                                            //缓冲变量，从缓冲区读数据
	uint32_t tmpLen = 0;                                        //缓冲变量，从缓冲区读取数据的长度
	ProtocolDataHead_stu_t *pPacketHead = NULL;
	uint8_t buff[64];

	//查询缓冲区是否有数据
	tmpLen = OSAL_RingBufferGetValidSize(fingerveinRx_rbHandle);
	if (tmpLen == 0)
	{
		/* 连续3次没有读取到数据（30ms） */
		if (++getPacketTimeoutCnt >= 3)
		{
			if(CmdPacketRxInfo.protocolCount)
			{
				FINGERVEIN_TASK_LOG("fingervein recv timeout\r\n");
			}
			getPacketTimeoutCnt = 0;
			CmdPacketRxInfo.protocolCount = 0;                      //清0解析计数
			packetLen = 0;											//清0解析包长度
		}
	  return NULL;
	}

	pCnt = &(CmdPacketRxInfo.protocolCount);	                  //解析计数
	protocolBuff = CmdPacketRxInfo.protocolBuf;                 //解析缓存
	pPacketHead = (ProtocolDataHead_stu_t *)protocolBuff;

	// __FINGERVEIN_TASK_DEBUG_LOG("Uart Fingervein RX Len = %d\r\n", tmpLen);
	for (; tmpLen; tmpLen--)                                    //循环读字节
	{
		OSAL_RingBufferRead(fingerveinRx_rbHandle, &tmpData);   //读取到一个字节数据
		// __FINGERVEIN_TASK_DEBUG_LOG(" %02X", tmpData);
		if(*pCnt == 0)
		{
			if (tmpData == (PROTOCOL_STX >> 8))        //帧数据头高字节
			{
				protocolBuff[0] = tmpData;
				*pCnt = 1;  
			}
			else if (tmpData == HELLO_OK)
			{
				protocolBuff[0] = tmpData;
				*pCnt = 0;
				return protocolBuff;

			}
		}
		else if(*pCnt == 1)
		{
			if (tmpData == (PROTOCOL_STX & 0x00FF))                 //帧数据头低字节
			{
				protocolBuff[1] = tmpData;
				*pCnt = 2;
			}
    	}
		else if(*pCnt > 1)
		{
			protocolBuff[*pCnt] = tmpData;
			*pCnt = *pCnt + 1;
			if(*pCnt == 9)
			{
				// 不需要大小端转换
				// FINGERVEIN_TASK_LOG("datalen %04x, %04x", pPacketHead->dataLen,pPacketHead->stx);
				// packetLen = pPacketHead->dataLen + 9;  //包总长，data + 包头(2) + chipAddr(4) + msgType(1) + dataLen(2)
				packetLen = pPacketHead->dataLen;
				packetLen = SWAP16(packetLen) + 9;
				// FINGERVEIN_TASK_LOG("packetLen = %d\r\n", packetLen);
			}
			if(packetLen == *pCnt)
			{
				CalcSum = Fingervein_CalcCheckSum(protocolBuff + CHECK_SUM_DATA_START, (uint8_t)(packetLen - 9) + CHECK_SUN_LEN_ADD);
				// FINGERVEIN_TASK_LOG("Uart Fingervein CalcSum = %#x", CalcSum);
				recvSum = ((protocolBuff[packetLen - 2]) << 8) + protocolBuff[packetLen - 1];			//2bytes的校验和，高字节在前低字节在后
				// FINGERVEIN_TASK_LOG("Uart Fingervein recvSum = %#x", recvSum);
				if (recvSum == CalcSum) 	//判断校验和
				{
					FINGERVEIN_TASK_DEBUG_LOG("\r\n");
					__FINGERVEIN_TASK_DEBUG_LOG("FingerveinTask Receive:");
					for (int i = 0; i < packetLen; i++)
					{
						__FINGERVEIN_TASK_DEBUG_LOG(" %02X", protocolBuff[i]);
					}
					__FINGERVEIN_TASK_DEBUG_LOG("\r\n");
					*pCnt = 0;
					packetLen = 0;											//清0解析包长度
					return protocolBuff;
				}
				else
				{
					FINGERVEIN_TASK_LOG("CRC ERR!FingerveinTask Receive:");
					for (int i = 0; i < packetLen; i++)
					{
						__FINGERVEIN_TASK_DEBUG_LOG(" %02X", protocolBuff[i]);
					}
					__FINGERVEIN_TASK_DEBUG_LOG("\r\n");
					*pCnt = 0;
					packetLen = 0;											//清0解析包长度
					return NULL;
				}			
			}
		}
	}
	return NULL;
}


/**
  * @brief  故障处理
  * @note
  * @param  err：是否故障
  * @return void
  */
static void err_process(uint8_t err)
{
	// TODO 待后续增加
	// static uint8_t err_flag = 0xff;
    // if (err != err_flag)
    // {
    //     err_flag = err;
    //     OSAL_MessagePublishErrorCode(ERRCODE_TYPE_FACE, err_flag);
    // }
}


/**
  * @brief  发消息给队列
  *
  * @param  cmd：命令
  * @param  pData：数据域指针
  * @param  dataLen：数据长度
  * @param  cb：reply回调函数
  */
static void Fingervein_SendCmdToRingBuff(uint8_t cmd, uint8_t *pData, uint16_t dataLen, FingerveinMessageCallback_fun_t cb, uint32_t timeout)
{
	FingerveinTxCmdMsg_stu_t msgTxData;
	msgTxData.cmd = cmd;
	msgTxData.cb = cb;
	msgTxData.timeout = timeout;
	msgTxData.dataLen = dataLen;
	memcpy(msgTxData.dataBuf, pData, dataLen);
	if (cmd == CMD_HELLO)			//握手命令做一个特殊处理
	{
		if (operate_rbHandle != NULL)
		{
			if (OSAL_RingBufferWrite(operate_rbHandle, &msgTxData) == ERROR)
			{
				FINGERVEIN_TASK_LOG("operate_rbHandle RingBuffer Write error cmd = %#x\r\n", cmd);
			}
		}
	}
	else
	{
		if (fingerveinTx_rbHandle != NULL)
		{
			// FINGERVEIN_TASK_LOG("fingerveinTx_rbHandle Write cmd = %#x\r\n", cmd);
			if (OSAL_RingBufferWrite(fingerveinTx_rbHandle, &msgTxData) == ERROR)
			{
				FINGERVEIN_TASK_LOG("fingerveinTx_rbHandle RingBuffer Write error cmd = %#x\r\n", cmd);
			}
		}
	}
}


/**
  * @brief 定时检测指静脉录入时手指是否正确放置
  * @note
  * @param
  * @return
  */
static void Fingervein_Get_FingerStatus(void)
{
	FingerveinMsg_t fingerveinMsg;

	//Touch_out触摸信号中断后，进行首次判断
	if ((process_Start_Flag == SET) && (finger_Touch_OK_Flag == RESET))
	{
		(fingervein_Status_Data.finger_out_count)++;		//计数+1；
		FINGERVEIN_TASK_LOG("fingervein_Enroll: enroll_num = %d, finger_out_count = %d\r\n", fingervein_Status_Data.enroll_num, fingervein_Status_Data.finger_out_count);

		if (fingervein_Status_Data.finger_out_count < 4)
		{
			fingerveinMsg.action = FINGERVEIN_ACTION_ENTER_AGAIN;
			fingerveinMsg.fingerveinNumber = 0xEE;							//打断方式播放提示“请用手指接触指静脉两端触点”
			OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

			// 延时一段时间之后再次检测
#if defined(BOARD_M30J0_ADD_FINGERVEIN_WITH_FPT)   
			OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_CHECK_FINGER_STATUS, 8000, EVT_PRIORITY_MEDIUM);	//KDS的K8603项目，延长检测手指状态的时间间隔；
#else
			OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_CHECK_FINGER_STATUS, 5000, EVT_PRIORITY_MEDIUM);
#endif
		}
		else	//连续三次未正确放入手指，超时退出；
		{
			FINGERVEIN_TASK_LOG("fingervein_Enroll: No finger touch,timeout exit!\r\n");
			fingervein_Status = FVN_STATUS_ENROLL_FAILED;                  //切换到录入失败
			/*用户长时间未放手指，超时，判定录入失败，此时需要发送取消指令给指静脉模块，因为指静脉模块内部超时时间还没到达，仍出去自动录入的流程中*/
			Fingervein_Cmd_Abort();
		}
	}
	return;
}


/**
  * @brief 指静脉单次录入采图结束后，手指没有离开模块,上报应用层播报语音提醒；
  * @note
  * @param
  * @return
  */
static void Fingervein_Wait_Finger_Away(void)
{
	FingerveinMsg_t fingerveinMsg;
	wait_Finger_Away_Count++;

	if (wait_Finger_Away_Count >= FINGERVEIN_ENROLL_WAIT_FINGER_AWAY_NUMS)									//等待手指移开超时，退出注册流程；	
	{
		FINGERVEIN_TASK_LOG("fingervein_Enroll: Wait_Finger_Away,timeout exit!\r\n");
		fingervein_Status = FVN_STATUS_ENROLL_FAILED;                  //切换到录入失败
		/*用户采图后一直未松开手指，超时，判定录入失败，此时需要发送取消指令给指静脉模块，因为指静脉模块内部超时时间还没到达，仍出去自动录入的流程中*/
		Fingervein_Cmd_Abort();
	}
	else
	{
		fingerveinMsg.action = FINGERVEIN_ACTION_WAIT_FINGER_AWAY;
		fingerveinMsg.fingerveinNumber = 0xff;							//非打断方式播放提示“请拿开手指”
		OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

		// 延时一段时间之后再次检测
		OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_WAIT_FINGER_AWAY, FINGERVEIN_ENROLL_WAIT_FINGER_AWAY_TIME, EVT_PRIORITY_MEDIUM);
	}
	return;
}


/**
  * @brief 指静脉的握手命令回调处理函数
  * @note
  * @param
  * @return
  */
static void Fingervein_Cmd_Hello_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	if (result == TX_RES_TIMEOUT)		//指静脉握手命令超时
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		module_Ready_Flag = SET;
		//TODO上报指静脉的错误码
		
		return;
	}
	

	if (data[0] == FINGERVEIN_RES_SUCCESS)
	{
		FINGERVEIN_TASK_LOG("Fingervein Hello OK\r\n");
	}
	else if(data[0] == FINGERVEIN_RES_FAILE) 
	{
		FINGERVEIN_TASK_LOG("Fingervein Hello faild\r\n");
	}
	CmdPacketTxInfo.status = TX_STA_IDLE;
	module_Ready_Flag = SET;
	return;
}

/**
  * @brief 指静脉的自动注册命令回调处理函数
  * @note
  * @param
  * @return
  */
static void Fingervein_Cmd_AutoEnroll_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	FingerveinMsg_t fingerveinMsg;

	if (result == TX_RES_TIMEOUT)
	{
		fingervein_Status = FVN_STATUS_ENROLL_FAILED;                  //切换到录入失败
		CmdPacketTxInfo.status = TX_STA_IDLE;
		return;
	}
	
	//先判断指静脉上报的结果是否为超时,如果是超时，直接结束退出自动注册
	if (data[0] == FINGERVEIN_RES_TIMEOUT)
	{
		FINGERVEIN_TASK_LOG("Cmd_AutoEnroll ACK Timeout: param[1] = %#x, param[2] = %#x,\r\n", data[1], data[2]);
		fingervein_Status = FVN_STATUS_ENROLL_FAILED;                  //切换到录入失败
		return;
	}
	
	// 指静脉模块首先回复自动注册命令的合法性,INFO recv:[0xef 0x01 0xff 0xff 0xff 0xff 0x07 0x00 0x05 0x00 0x00 0x00 0x00 0x0c ]
	if ((data[1] == 0x00) && (data[2] == 0x00))
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//指令合法
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll ACK success\r\n");
			CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();				//更新串口命令发送时间戳，防止超时；
		}
		else
		{
			//指令失败，
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll ACK failed, errorCode = %#x\r\n", data[0]);
			fingervein_Status = FVN_STATUS_ENROLL_FAILED;                  //切换到录入失败
		}
		return;
	}

	// 手指已接触指静脉模块两端触点，开始录入采图流程回复
	if (data[1] == 0x07)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			finger_Touch_OK_Flag = SET;											//手指已正确接触指静脉两端触点，标志置为真；
			OSAL_EventDelete(COMP_FINGERVEIN, EVENT_CHECK_FINGER_STATUS);			//手指按压正确，删除定时检测手指状态的事件；

			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = finger_In,count = %d\r\n", data[2]);
			if (data[2] == 1 || data[2] == 2)
			{
				fingerveinMsg.action = FINGERVEIN_ACTION_FINGER_IN;
				fingerveinMsg.fingerveinNumber = 0xA1;							//用0XA1表示录入时候播报“向左右滑动整个手指”，打断方式播报
				OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  	//上报应用层检测到指静脉手指触摸有效

				/* 手指按压正确，开始滑动采图，定时一段时间后提示结束采图； */ 
				OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_ENROLL_GET_IMAGE_TIMER, FINGERVEIN_ENROLL_GEI_IMAGE_TIME, EVT_PRIORITY_MEDIUM);
				Enroll_Get_Image_Timer_On_Flag = SET;

			}
			else if (data[2] == 3 || data[2] == 4)
			{
				fingerveinMsg.action = FINGERVEIN_ACTION_FINGER_IN;
				fingerveinMsg.fingerveinNumber = 0xA2;							//用0XA2表示录入时候播报“手指向下倾斜，向左右两端滑动整根手指”，打断方式播报
				OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

				/* 手指按压正确，开始滑动采图，定时一段时间后提示结束采图； */ 
				OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_ENROLL_GET_IMAGE_TIMER, FINGERVEIN_ENROLL_GEI_IMAGE_TIME + 2000, EVT_PRIORITY_MEDIUM);
				Enroll_Get_Image_Timer_On_Flag = SET;
			}
			else if (data[2] == 5 || data[2] == 6)
			{
				fingerveinMsg.action = FINGERVEIN_ACTION_FINGER_IN;
				fingerveinMsg.fingerveinNumber = 0xA3;							//用0XA3表示录入时候播报“手指向上倾斜，向左右两端滑动整根手指”，打断方式播报
				OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

				/* 手指按压正确，开始滑动采图，定时一段时间后提示结束采图； */
				OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_ENROLL_GET_IMAGE_TIMER, FINGERVEIN_ENROLL_GEI_IMAGE_TIME + 2000, EVT_PRIORITY_MEDIUM);		//保持一样的时间间隔
				Enroll_Get_Image_Timer_On_Flag = SET;
			}		
		}
		else
		{
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = finger touch failed, errorCode = %#x\r\n", data[0]);
		}
		return;
	}
	
	//判断手指离开回复
	if (data[1] == 0x03)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			if (data[2] != 0)
			{
				fingervein_Status_Data.enroll_num = data[2];							//手指离开成功，更新录入次数；
				if (Enroll_Get_Image_Timer_On_Flag == SET)								//滑动采图的定时事件时间未到达，用户提前拿开手指
				{
					FINGERVEIN_TASK_LOG("Cmd_AutoEnroll: finger away early!\r\n");
					OSAL_EventDelete(COMP_FINGERVEIN, EVENT_ENROLL_GET_IMAGE_TIMER);
					Enroll_Get_Image_Timer_On_Flag = RESET;
					if (fingervein_Status_Data.enroll_num == AUTO_ENROLL_MAX_NUMS)		//第六次采图结束，不用播报“松开手指，继续录入”
					{
						fingerveinMsg.action = FINGERVEIN_ACTION_ENROLL_GET_IMAGE_OK;
						fingerveinMsg.fingerveinNumber = 0xF6;
						OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  //上报应用层指静脉结束单次采图
		
					}
					else
					{
						fingerveinMsg.action = FINGERVEIN_ACTION_ENROLL_GET_IMAGE_OK;
						fingerveinMsg.fingerveinNumber = 0xff;
						OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  //上报应用层指静脉结束单次采图
					}
				}
				finger_Touch_OK_Flag = RESET;											//单次采图结束，手指已离开，标志置为假；
				//手指离开成功，上报应用层
				FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = finger_Out:count = %d\r\n", data[2]);
				fingervein_Status = FVN_STATUS_FINGER_AWAY;                 			//指静脉处理流程，切换到手指离开成功
			}
		}
		else
		{
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = finger away failed, errorCode = %#x\r\n", data[0]);
		}
		return;	
	}

	//自动注册采图回复
	if (data[1] == 0x01)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//采图成功，上报应用层
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = get_Image_Ok,count = %d\r\n", data[2]);
			CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();				//更新串口命令发送时间戳，防止超时；
		}
		else
		{
			//采图错误，
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = get_Image_Failed,errorCode = %#x\r\n", data[0]);
		}
		return;	
	}
	
	//生成特征回复
	if (data[1] == 0x02)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//生成特征成功
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = image_Extract_Ok,:count = %d\r\n", data[2]);
		}
		else
		{
			//生成特征错误，
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = image_Extract_Failed, errorCode = %#x\r\n", data[0]);
		}
		return;	
	}


	//合并模板回复
	if ((data[1] == 0x04) && (data[2] == 0xF0))
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//合并模板成功
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = register_Template_Ok\r\n");
		}
		else
		{
			//生成特征错误，
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = register_Template_Failed, errorCode = %#x\r\n", data[0]);
			fingervein_Status = FVN_STATUS_ENROLL_FAILED;                 			 //指静脉处理流程，切换到录入失败状态
		}
		return;	
	}

	//重复注册检验回复
	if ((data[1] == 0x05) && (data[2] == 0xF1))
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//合并模板成功
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = register_Finger_ID_Ok\r\n");
		}
		else
		{
			//生成特征错误，
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = register_Finger_ID_Failed, errorCode = %#x\r\n", data[0]);
			fingervein_Status = FVN_STATUS_ENROLL_FAILED;                 			 //指静脉处理流程，切换到录入失败状态
		}
		return;	
	}

	//存储模板回复
	if ((data[1] == 0x06) && (data[2] == 0xF2))
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//存储模板成功，上报应用层
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = save_Template_Ok\r\n");
			fingervein_Status = FVN_STATUS_ENROLL_SUCCESS;                 			 //指静脉处理流程，切换到录入成功状态
		}
		else
		{
			//存储模板错误，
			FINGERVEIN_TASK_LOG("Cmd_AutoEnroll:Res = save_Template_Failed, errorCode = %#x\r\n", data[0]);
			fingervein_Status = FVN_STATUS_ENROLL_FAILED;                 			 //指静脉处理流程，切换到录入失败状态
		}
		return;	
	}

	return;
}

#define CMD_AUTOVERIFY_ACK_DATA_LEN		6			//指静脉的自动验证命令回复包的数据长度（不包括校验和的长度）
/**
  * @brief 指静脉的自动验证命令回调处理函数
  * @note
  * @param
  * @return
  */
static void Fingervein_Cmd_AutoVerify_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	if (result == TX_RES_TIMEOUT)
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		fingervein_Status = FVN_STATUS_END;                  //切换到结束
		return;
	}

	if (len != CMD_AUTOVERIFY_ACK_DATA_LEN)
	{
		FINGERVEIN_TASK_LOG("Cmd_AutoVerify ack data len error,len = %d\r\n", len);
		return;
	}
	
	// 指静脉模块首先回复自动验证命令的合法性,INFO recv:[0xef 0x01 0xff 0xff 0xff 0xff 0x07 0x00 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0f ]
	if (data[1] == 0x00)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//指令合法
			FINGERVEIN_TASK_LOG("Cmd_AutoVerify ACK success\r\n");
		}
		else
		{
			//指令执行错误
			FINGERVEIN_TASK_LOG("Cmd_AutoVerify ACK faid, error = %#x\r\n", data[0]);
			fingervein_Status = FVN_STATUS_END;                  //切换到结束
		}
		return;
	}

	//自动验证采图回复
	if (data[1] == 0x01)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//采图成功，上报应用层
			FINGERVEIN_TASK_LOG("Cmd_AutoVerify: Res = get image ok\r\n");
			fingervein_Status = FVN_STATUS_VERIFY_GET_IMAGE_OK;                 			 			//指静脉处理流程，切换到采图成功状态
			return;
		}
		else
		{
			//采图错误，
			FINGERVEIN_TASK_LOG("Cmd_AutoVerify: Res = get image failed,error = %#x\r\n", data[0]);
			if (data[0] == 0x26)
			{
				fingervein_Status = FVN_STATUS_VERIFY_FAILED;                 			 		//验证采图超时，指静脉处理流程，切换到验证失败状态
			}
			else
			{
				fingervein_Status = FVN_STATUS_VERIFY_GET_IMAGE_OK;                 			 //验证采图成功，但特征生成失败，指静脉处理流程，借用切换到采图成功状态，等待搜索结果的回包
			}
			return;
		}	
	}

	//自动验证比对回复
	if (data[1] == 0x05)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)
		{
			//搜索ID成功，上报应用层
			FINGERVEIN_TASK_LOG("Cmd_AutoVerify: Res = search ok,ID = %d, score = %d\r\n",data[3], data[5]);	//2byte，都是直接取低字节
			template_Verify_Num = data[3];
			fingervein_Status = FVN_STATUS_VERIFY_SUCCESS;                 			 				//指静脉处理流程，切换到验证成功状态
			return;
		}
		else
		{
			//验证失败，
			if (data[0] == 0x09)
			{
				FINGERVEIN_TASK_LOG("Cmd_AutoVerify: Res = Verify failed,error = %#x, no finger match\r\n", data[0]);
			}
			else
			{
				FINGERVEIN_TASK_LOG("Cmd_AutoVerify: Res = Verify failed,error = %#x\r\n", data[0]);
			}	
			fingervein_Status = FVN_STATUS_VERIFY_FAILED;                 			 				//指静脉处理流程，切换到验证失败状态
			return;
		}	
	}

	//自动验证成功，模板更新结果回复，对指静脉验证结果没有影响；
	if (data[1] == 0x06)
	{
		FINGERVEIN_TASK_LOG("Cmd_AutoVerify: update_template, res = %#x\r\n", data[0]);
		fingervein_Status = FVN_STATUS_END;                 			 				//指静脉处理流程，切换到结束状态
		return;
	}
}

#define CMD_DEL_TEMPLATE_ACK_DATA_LEN		1			//指静脉删除模板命令回复包的数据长度（不包括校验和的长度）
/**
  * @brief 指静脉删除单个模板回调处理函数
  * @note
  * @param
  * @return
  */
static void Fingervein_Cmd_DelTemplate_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	if (result == TX_RES_TIMEOUT)
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		return;
	}

	if (len != CMD_DEL_TEMPLATE_ACK_DATA_LEN)
	{
		FINGERVEIN_TASK_LOG("Cmd_DelTemplate ack data len error,len = %d\r\n", len);
		return;
	}

	if (data[0] == FINGERVEIN_RES_SUCCESS)
	{
		//删除成功，
		FINGERVEIN_TASK_LOG("Cmd_DelOneTemp:Res = success\r\n");	
	}
	else
	{
		//删除失败，
		FINGERVEIN_TASK_LOG("Cmd_DelOneTemp:Res = failed,errorCode = %#x\r\n", data[0]);
	}
	CmdPacketTxInfo.status = TX_STA_IDLE;
	return;		
}


/**
  * @brief 指静脉清空指静脉库回调处理函数
  * @note  
  * @param
  * @return
  */
static void Fingervein_Cmd_DelAllTemplate_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	if (result == TX_RES_TIMEOUT)
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		return;
	}

	if (data[0] == FINGERVEIN_RES_SUCCESS)
	{
		//删除成功，
		FINGERVEIN_TASK_LOG("Cmd_DelAllTemp:Res = success\r\n");	
	}
	else
	{
		//删除失败，
		FINGERVEIN_TASK_LOG("Cmd_DelAllTemp:Res = failed,errorCode = %#x\r\n", data[0]);
	}
	CmdPacketTxInfo.status = TX_STA_IDLE;
	return;	
}


/**
  * @brief 指静脉获取Touchstatus回调处理函数
  * @note
  * @param
  * @return
  */
#if defined(BOARD_M30J0_ADD_FINGERVEIN_WITH_FPT)		//为KDS的K8603的项目指纹与指静脉验证误触问题做适配，修改验证指静脉时候手指一直单边触摸的提示语音间隔；
static void Fingervein_Cmd_GetTouchStatus_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	FingerveinMsg_t fingerveinMsg;

	if (result == TX_RES_TIMEOUT)
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		getTouchStatus_Start_Flag = RESET;
		return;
	}

	if (fingervein_Status_Data.mode == WORK_MODE_VERIFY)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)		//获取Touch状态成功
		{	
			getTouchStatus_Count++;
			if (data[1] == TOUCH_SUCCESS)			//手指接触指静脉模块两端触点，触摸有效
			{
				if (process_Start_Flag == RESET)		//判断是否已经处于验证流程，防止重复发送验证指令
				{
					FINGERVEIN_TASK_LOG("Fingervein touch ok, start to verify\r\n");	
					process_Start_Flag = SET;
					fingervein_Status = FVN_STATUS_INIT;										//指静脉流程切换到初始化状态；
					OSAL_EventRepeatCreate(COMP_FINGERVEIN, EVENT_FINGERVEIN_PROCESS, FINGERVEIN_PROCESSOR_TIME, EVT_PRIORITY_MEDIUM);
					getTouchStatus_Start_Flag = RESET;
					CmdPacketTxInfo.status = TX_STA_IDLE;
					return;
				}
			}		
			else if (data[1] == ONLY_LEFT_TOUCH || data[1] == ONLY_RIGHT_TOUCH)			//手指接触到指静脉模块的单端触点，触摸无效
			{
				if (getTouchStatus_Count == 17 ||  getTouchStatus_Count == 60)			//定时播报语音提醒“请用手指接触指静脉两端触点”；
				{
					FINGERVEIN_TASK_LOG("Fingervein verify: finger touch not correct!\r\n");
					fingerveinMsg.action = FINGERVEIN_ACTION_ENTER_AGAIN;					
					fingerveinMsg.fingerveinNumber = 0xEE;							//打断模式播放
					OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  	//上报应用层手指没有接触成功，
				}
				else if (getTouchStatus_Count > 75)
				{
					getTouchStatus_Count = 0;
					getTouchStatus_Start_Flag = RESET;
					CmdPacketTxInfo.status = TX_STA_IDLE;
					return;
				}
				OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_GET_TOUCH_STATUS, 100, EVT_PRIORITY_MEDIUM);
				getTouchStatus_Start_Flag = RESET;
				CmdPacketTxInfo.status = TX_STA_IDLE;
				return;	
			}
			else
			{
				if (getTouchStatus_Count < 8)			//手指单边接触又很快拿开了
				{
					FINGERVEIN_TASK_LOG("Fingervein verify: finger_Out!\r\n");
				}
			}	
		}
		else
		{
			//获取Status失败，
			FINGERVEIN_TASK_LOG("Fingervein GetTouchStatus failed,error = %#x\r\n", data[0]);
		}
	}
	getTouchStatus_Start_Flag = RESET;
	CmdPacketTxInfo.status = TX_STA_IDLE;
	return;
}
#else
static void Fingervein_Cmd_GetTouchStatus_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	FingerveinMsg_t fingerveinMsg;

	if (result == TX_RES_TIMEOUT)
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		getTouchStatus_Start_Flag = RESET;
		return;
	}

	if (fingervein_Status_Data.mode == WORK_MODE_VERIFY)
	{
		if (data[0] == FINGERVEIN_RES_SUCCESS)		//获取Touch状态成功
		{	
			getTouchStatus_Count++;
			if (data[1] == TOUCH_SUCCESS)			//手指接触指静脉模块两端触点，触摸有效
			{
				if (process_Start_Flag == RESET)		//判断是否已经处于验证流程，防止重复发送验证指令
				{
					FINGERVEIN_TASK_LOG("Fingervein touch ok, start to verify\r\n");	
					process_Start_Flag = SET;
					fingervein_Status = FVN_STATUS_INIT;										//指静脉流程切换到初始化状态；
					OSAL_EventRepeatCreate(COMP_FINGERVEIN, EVENT_FINGERVEIN_PROCESS, FINGERVEIN_PROCESSOR_TIME, EVT_PRIORITY_MEDIUM);
					getTouchStatus_Start_Flag = RESET;
					CmdPacketTxInfo.status = TX_STA_IDLE;
					return;
				}
			}		
			else if (data[1] == ONLY_LEFT_TOUCH || data[1] == ONLY_RIGHT_TOUCH)			//手指接触到指静脉模块的单端触点，触摸无效
			{
				if (getTouchStatus_Count == 8 ||  getTouchStatus_Count == 62)			//定时播报语音提醒“请用手指接触指静脉两端触点”；
				{
					FINGERVEIN_TASK_LOG("Fingervein verify: finger touch not correct!\r\n");
					fingerveinMsg.action = FINGERVEIN_ACTION_ENTER_AGAIN;					
					fingerveinMsg.fingerveinNumber = 0xEE;							//打断模式播放
					OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  	//上报应用层手指没有接触成功，
				}
				else if (getTouchStatus_Count > 75)
				{
					getTouchStatus_Count = 0;
					getTouchStatus_Start_Flag = RESET;
					CmdPacketTxInfo.status = TX_STA_IDLE;
					return;
				}
				OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_GET_TOUCH_STATUS, 50, EVT_PRIORITY_MEDIUM);
				getTouchStatus_Start_Flag = RESET;
				CmdPacketTxInfo.status = TX_STA_IDLE;
				return;	
			}
			else
			{
				if (getTouchStatus_Count < 8)			//手指单边接触又很快拿开了
				{
					FINGERVEIN_TASK_LOG("Fingervein verify: finger_Out!\r\n");
					fingerveinMsg.action = FINGERVEIN_ACTION_ENTER_AGAIN;					
					fingerveinMsg.fingerveinNumber = 0xEE;							//打断模式播放
					OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  	//上报应用层手指没有接触成功，
				}
			}	
		}
		else
		{
			//获取Status失败，
			FINGERVEIN_TASK_LOG("Fingervein GetTouchStatus failed,error = %#x\r\n", data[0]);
		}
	}
	getTouchStatus_Start_Flag = RESET;
	CmdPacketTxInfo.status = TX_STA_IDLE;
	return;
}
#endif


/**
  * @brief 指静脉取消命令回调处理函数
  * @note
  * @param
  * @return
  */
static void Fingervein_Cmd_Abort_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	if (result == TX_RES_TIMEOUT)
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		return;
	}

	if (data[0] == FINGERVEIN_RES_SUCCESS)
	{
		//取消成功，
		FINGERVEIN_TASK_LOG("Cmd_Abort:Res = success\r\n");	
	}
	else
	{
		//取消失败，
		FINGERVEIN_TASK_LOG("Cmd_Abort:Res = failed,errorCode = %#x\r\n", data[0]);
	}
	CmdPacketTxInfo.status = TX_STA_IDLE;
	return;	
}


#define VERSION_START	14			//获取指静脉版本号指令，从模块返回的字符串中读取版本号偏移量
/**
  * @brief 指静脉获取版本号命令回调处理函数
  * @note	版本号格式为：901VP_FVN$16_Vx.xx.xxx,，只保存“Vx.xx.xxx”这个9位，包括“.”;
  * @param
  * @return
  */
static void Fingervein_Cmd_GetVersion_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	uint8_t versionBuff[FINGERVEIN_VERSION_LEN + 1] = {0};				//长度+1是要预留字符串的结束符
	uint8_t versionReadBuff[FINGERVEIN_VERSION_LEN + 1] = {0};
	uint8_t lockModelBuff[LOCKMODEL_LEN + 1] = {0};
	if (result == TX_RES_TIMEOUT)
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		return;
	}

	//模组的回复帧[EF 01 FF FF FF FF 07 00 1A 00 39 30 31 56 50 5F 46 56 4E 24 31 36 5F 56 31 2E 30 31 2E 30 30 32 00 05 6A ]
	if (data[0] == FINGERVEIN_RES_SUCCESS)
	{
		//获取版本号成功
		memcpy(lockModelBuff, data + 1, LOCKMODEL_LEN);											//拷贝lockmodel
		memcpy(versionBuff, data + VERSION_START, FINGERVEIN_VERSION_LEN);			//拷贝指静脉版本号

		OSAL_NvRead(OSAL_OFFSET(NvFingervein_stu_t, fingerveinVersion), versionReadBuff, FINGERVEIN_VERSION_LEN);
		if (strncmp((char *)versionBuff, (char *)versionReadBuff, FINGERVEIN_VERSION_LEN) != 0)
		{
			//将新的指静脉固件版本更新到NV
			OSAL_NvWrite(OSAL_OFFSET(NvFingervein_stu_t, lockModel), lockModelBuff, LOCKMODEL_LEN);
			OSAL_NvWrite(OSAL_OFFSET(NvFingervein_stu_t, fingerveinVersion), versionBuff, FINGERVEIN_VERSION_LEN);

		}
		FINGERVEIN_TASK_LOG("Cmd_GetVersion:Res = success, model = %s, fingervein version = %s\r\n", (char *)lockModelBuff, (char *)versionBuff);	
	}
	else
	{
		//获取版本号失败，
		FINGERVEIN_TASK_LOG("Cmd_GetVersion:Res = failed,errorCode = %#x\r\n", data[0]);
	}
	CmdPacketTxInfo.status = TX_STA_IDLE;
	return;	
}


/**
  * @brief 指静脉整机测试回调处理函数
  * @note
  * @param
  * @return
  */
static void Fingervein_Cmd_AteTest_Callback(uint8_t result, uint8_t *data, uint8_t len)
{
	FingerveinMsg_t fingerveinMsg;
	if (result == TX_RES_TIMEOUT)
	{
		CmdPacketTxInfo.status = TX_STA_IDLE;
		return;
	}

	if (data[0] == FINGERVEIN_RES_SUCCESS)
	{
		//命令执行成功，
		FINGERVEIN_TASK_LOG("Cmd_AteTest result = %#x\r\n", data[1]);

		fingerveinMsg.action = FINGERVEIN_ACTION_ATE_TEST_RESULT;					
		fingerveinMsg.fingerveinNumber = data[1];						//测试结果
		OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  	//上报ATE，
		
	}

	CmdPacketTxInfo.status = TX_STA_IDLE;
	return;	
}



/**
  * @brief  指静脉CMD结果回调
  * @param  result：结果
  * @param  data：返回的数据
  * @param  len: 数据长度
  * @note
  */
static void Fingervein_Cmd_Callback(uint8_t cmd, uint8_t result, uint8_t *data, uint8_t len)
{
	switch (cmd)
	{
		case CMD_HELLO:
			Fingervein_Cmd_Hello_Callback(result, data, len);
		break;

		case CMD_AUTO_ENROLL:
			Fingervein_Cmd_AutoEnroll_Callback(result, data, len);
		break;

		case CMD_AUTO_VERIFY:
			Fingervein_Cmd_AutoVerify_Callback(result, data, len);
		break;

		case CMD_DEL_TEMPLATE:
			Fingervein_Cmd_DelTemplate_Callback(result, data, len);
		break;

		case CMD_DEL_ALL_TEMPLATE:
			Fingervein_Cmd_DelAllTemplate_Callback(result, data, len);
		break;
	
		case CMD_GET_TOUCH_STATUS:
			Fingervein_Cmd_GetTouchStatus_Callback(result, data, len);
		break;

		case CMD_ABORT:
			Fingervein_Cmd_Abort_Callback(result, data, len);
		break;

		case CMD_GET_VERSION:
			Fingervein_Cmd_GetVersion_Callback(result, data, len);
		break;

		case CMD_ATE_TEST:
			Fingervein_Cmd_AteTest_Callback(result, data, len);
		break;

		default:
		break;
	}
}


/**
  * @brief  指静脉握手指令0x35H
  * @note
  *
  * @param  
  */
static void Fingervein_Cmd_Hello(void)
{
	uint8_t param[5] = {0};
	param[0] = CMD_HELLO;
	Fingervein_SendCmdToRingBuff(CMD_HELLO, param, 1, Fingervein_Cmd_Callback, HELLO_CMD_TIMEOUT);
}

/**
  * @brief  指静脉自动注册指令：31H
  * @note
  *
  * @param  
  */
static void Fingervein_Cmd_AutoEnroll(void)
{
	FINGERVEIN_TASK_LOG("Fingervein send Cmd_AutoEnroll = %#X\r\n", CMD_AUTO_ENROLL);
	uint8_t param[10] = {0};
	param[0] = CMD_AUTO_ENROLL;			//1byte指令代码
	param[1] = 0x00;					//2byte录入ID，高字节
	param[2] = template_Save_Num;			//2byte录入ID，低字节
	param[3] = 0x03;					//1byte录入次数，保留，默认为0x03，具体次数由指静脉底层算法决定；
	param[4] = 0x00;					//2byte录入参数，高字节
	param[5] = 0x08;					//2byte录入参数，低字节
	Fingervein_SendCmdToRingBuff(CMD_AUTO_ENROLL, param, 6, Fingervein_Cmd_Callback, ENROLL_CMD_TIMEOUT);
}


/**
  * @brief  指静脉自动验证指令32H
  * @note
  *
  * @param  
  */
static void Fingervein_Cmd_AutoVerify(void)
{
	FINGERVEIN_TASK_LOG("Fingervein send Cmd_AutoVerify = %#X\r\n", CMD_AUTO_VERIFY);
	uint8_t param[10] = {0};
	param[0] = CMD_AUTO_VERIFY;			//1byte指令代码
	param[1] = 0x04;					//1byte安全等级
	param[2] = 0xFF;					//2byte搜索ID范围，高字节
	param[3] = 0xFF;					//2byte搜索ID范围，低字节
	param[4] = 0x00;					//2byte验证参数，高字节
	param[5] = 0x01;					//2byte验证参数，低字节
	Fingervein_SendCmdToRingBuff(CMD_AUTO_VERIFY, param, 6, Fingervein_Cmd_Callback, VERIFY_CMD_TIMEOUT);
}


/**
  * @brief  指静脉删除模板指令：0CH
  * @note
  *
  * @param  
  */
static void Fingervein_Cmd_DelTemplate(uint8_t startNum, uint8_t nums)
{
	FINGERVEIN_TASK_LOG("Fingervein send Cmd_DelTemplate = %#X\r\n", CMD_DEL_TEMPLATE);
	uint8_t CmdParamBuff[sizeof(CmdParamPacket_stu_t) + MAX_CMD_PARAM_LEN] = {0};
	uint8_t buffLen = 0;
	CmdParamPacket_stu_t *pCmdBuff = (CmdParamPacket_stu_t *)CmdParamBuff;
	pCmdBuff->cmd = CMD_DEL_TEMPLATE;					//1byte指令代码
	buffLen++;
	pCmdBuff->param[0] = 0x00;							//高位,模板号PageID，共2byte
	buffLen++;
	pCmdBuff->param[1] = startNum;						//低位,模板号PageID，共2byte
	buffLen++;
	pCmdBuff->param[2] = 0x00;							//高位,删除个数，共2byte
	buffLen++;
	pCmdBuff->param[3] = nums;							//低位,删除个数，共2byte
	buffLen++;

	Fingervein_SendCmdToRingBuff(CMD_DEL_TEMPLATE, CmdParamBuff, buffLen, Fingervein_Cmd_Callback, NORMAL_CMD_TIMEOUT);
}

/**
  * @brief  指静脉获取touch状态指令：54H
  * @note
  *
  * @param  
  */
static void Fingervein_Cmd_GetTouchStatus(void)
{
	FINGERVEIN_TASK_LOG("Fingervein send Cmd_GetTouchStatus = %#X\r\n", CMD_GET_TOUCH_STATUS);
	uint8_t param[10] = {0};
	param[0] = CMD_GET_TOUCH_STATUS;			//1byte指令代码
	Fingervein_SendCmdToRingBuff(CMD_GET_TOUCH_STATUS, param, 1, Fingervein_Cmd_Callback, NORMAL_CMD_TIMEOUT);
}


/**
  * @brief  指静脉清空指静脉库指令：0DH
  * @note   烧录程序后，首次上电，系统在进行NV初始化时候，会执行删除全部指静脉模板的命令；
  *
  * @param  
  */
static void Fingervein_Cmd_DelAllTemplate(void)
{
	FINGERVEIN_TASK_LOG("Fingervein send Cmd_DelAllTemp = %#X\r\n", CMD_DEL_ALL_TEMPLATE);
	uint8_t CmdParamBuff[sizeof(CmdParamPacket_stu_t) + MAX_CMD_PARAM_LEN] = {0};
	uint8_t buffLen = 0;
	CmdParamPacket_stu_t *pCmdBuff = (CmdParamPacket_stu_t *)CmdParamBuff;

	pCmdBuff->cmd = CMD_DEL_ALL_TEMPLATE;					//1byte指令代码
	buffLen++;
	Fingervein_SendCmdToRingBuff(CMD_DEL_ALL_TEMPLATE, CmdParamBuff, buffLen, Fingervein_Cmd_Callback, NORMAL_CMD_TIMEOUT);
}


/**
  * @brief  指静脉取消指令：30H
  * @note   
  *
  * @param  
  */
static void Fingervein_Cmd_Abort(void)
{
	FINGERVEIN_TASK_LOG("Fingervein send Cmd_Abort = %#X\r\n", CMD_ABORT);
	uint8_t param[10] = {0};
	param[0] = CMD_ABORT;			//1byte指令代码
	Fingervein_SendCmdToRingBuff(CMD_ABORT, param, 1, Fingervein_Cmd_Callback, NORMAL_CMD_TIMEOUT);
}


/**
  * @brief  读取模组软件版本版本号指令：61H
  * @note   版本号格式为：901VP_FVN$16_Vx.xx.xxx
  *
  * @param  
  */
static void Fingervein_Cmd_GetVersion(void)
{
	FINGERVEIN_TASK_LOG("Fingervein send Cmd_GetVersion = %#X\r\n", CMD_GET_VERSION);
	uint8_t CmdParamBuff[sizeof(CmdParamPacket_stu_t) + MAX_CMD_PARAM_LEN] = {0};
	uint8_t buffLen = 0;
	CmdParamPacket_stu_t *pCmdBuff = (CmdParamPacket_stu_t *)CmdParamBuff;

	pCmdBuff->cmd = CMD_GET_VERSION;					//1byte指令代码
	buffLen++;
	Fingervein_SendCmdToRingBuff(CMD_GET_VERSION, CmdParamBuff, buffLen, Fingervein_Cmd_Callback, NORMAL_CMD_TIMEOUT);
}

/**
  * @brief  指静脉整机测试指令：50H
  * @note
  *
  * @param  
  */
static void Fingervein_Cmd_AteTest(void)
{
	FINGERVEIN_TASK_LOG("Fingervein send Cmd_AteTest = %#X\r\n", CMD_ATE_TEST);
	uint8_t CmdParamBuff[sizeof(CmdParamPacket_stu_t) + MAX_CMD_PARAM_LEN] = {0};
	uint8_t buffLen = 0;
	CmdParamPacket_stu_t *pCmdBuff = (CmdParamPacket_stu_t *)CmdParamBuff;
	pCmdBuff->cmd = CMD_ATE_TEST;		//1byte指令代码
	buffLen++;							
	pCmdBuff->param[0] = 0x10;			//8byte的超时时间，最低位
	buffLen++;
	pCmdBuff->param[1] = 0x27;
	buffLen++;
	pCmdBuff->param[2] = 0x00;
	buffLen++;
	pCmdBuff->param[3] = 0x00;
	buffLen++;
	pCmdBuff->param[4] = 0x00;
	buffLen++;
	pCmdBuff->param[5] = 0x00;
	buffLen++;
	pCmdBuff->param[6] = 0x00;
	buffLen++;
	pCmdBuff->param[7] = 0x00;			//8byte的超时时间，最高位
	buffLen++;

	Fingervein_SendCmdToRingBuff(CMD_ATE_TEST, CmdParamBuff, buffLen, Fingervein_Cmd_Callback, ATE_TEST_CMD_TIMEOUT);
}


/**
  * @brief  解析读取的数据包
  * @note
  *
  * @param  pData:数据包
  */
static void Fingervein_ParseRxPacket(uint8_t *pData)
{
	// 处理指静脉模组启动时主动上0x55的Uart握手信号
	if (0X55 == pData[0])
	{
		module_Ready_Flag = SET;	//指静脉模组上电初始化成功，可以正常通信
		__FINGERVEIN_TASK_DEBUG_LOG("\r\n Fingervein Model is Ready,booting success! \r\n\r\n");
		return;
	}
	
	uint8_t relyLen = 0;	
	CmdPacket_stu_t *pPacketHead = (CmdPacket_stu_t *)pData;
	relyLen = (uint8_t)(SWAP16(pPacketHead->head.dataLen)) - 2;				//数据帧dataLen的长度包括了2位校验和的长度，所以要减2；注意大小端转换后，会直接改变原来数据的高低字节顺序；

	// 处理指静脉模组返回的数据包，并执行对应的回调操作；
	if (CmdPacketTxInfo.status == TX_STA_WAIT_ACK)
	{
		//向回调函数传的是除了PacketHead之外的内容，relyLen指的是除了校验和之外的数据长度
		Fingervein_Cmd_Callback(CmdPacketTxInfo.cmd, TX_RES_OK, pPacketHead->data, relyLen);
	}
	return;
}


/**
  * @brief  打印输出发送的命令包
  *
  * @note   
  */
static void Fingervein_PrintfTxData(uint8_t *pData, uint16_t len)
{
#if defined(DEBUG_EN)
	uint8_t strBuffer[66 * 3], i;
	if (len > 65)
		return; //格式化数组数量不能超过66*3
	for (i = 0; i < len; i++)
	{
		sprintf((char *)&strBuffer[i * 3], "%02X ", pData[i]);
	}
	sprintf((char *)&strBuffer[i * 3], "%s", "\r\n");
	FINGERVEIN_TASK_LOG("Fingervein send packet:%s", strBuffer);
#endif
}


/**
  * @brief  加载待发送的数据
  * @note   将要发出的数据，填入发送缓存区
  *
  * @param  pData：数据指针
  * @param  len：数据长度
  * @return 成功返回SUCCESS，失败返回ERROR
  */
static ErrorStatus Fingervein_LoadingDataToBeSent(uint8_t *pData, uint16_t len)
{
	if (len > 0x7FFF) //直接发
	{
		len &= 0x7FFF;
		Fingervein_PrintfTxData(pData, len);
		Device_Write(VHW_UART_FINGERVEIN, pData, len, 0);
		return SUCCESS;
	}
	return ERROR;
}


/**
  * @brief  重发指令包
  *
  * @note   
  */
static void Fingervein_ResendCmdPacket(void)
{
	uint32_t currentTime = OSAL_GetTickCount();
	uint8_t ret = TX_RES_TIMEOUT;

	if (CmdPacketTxInfo.status == TX_STA_WAIT_ACK) //当前状态正在等应答
	{
		if (CmdPacketTxInfo.cmd == CMD_HELLO)		//握手命令做超时重发
		{
			if (OSAL_PastTime(currentTime, CmdPacketTxInfo.timeStamp) > CmdPacketTxInfo.waitAckTimeout)
			{
				// if (CmdPacketTxInfo.sendCnt >= PROTOCOL_RESEND_TIMES)
				// {
					//ERR:超时
					FINGERVEIN_TASK_LOG("wait ack Time out cmd = %#2x,%#2x,%#2x,%#2x", CmdPacketTxInfo.cmd, currentTime, CmdPacketTxInfo.timeStamp, CmdPacketTxInfo.waitAckTimeout);
					if (pCmdCallback != NULL)
					{
						//各指令的对应reply的回调函数进行处理
						pCmdCallback(CmdPacketTxInfo.cmd, ret, NULL, 0);
						pCmdCallback = NULL;
					}
					CmdPacketTxInfo.status = TX_STA_IDLE;
				// }
				// else
				// {
				// 	//发送数据
    			// 	Fingervein_LoadingDataToBeSent(CmdPacketTxInfo.dataBuf, CmdPacketTxInfo.dataLen | 0x8000);
				// 	(CmdPacketTxInfo.sendCnt)++;
				// 	CmdPacketTxInfo.timeStamp = currentTime;
				// }	
			}
		}
		else			//其余命令暂不做重发机制
		{
			if (OSAL_PastTime(currentTime, CmdPacketTxInfo.timeStamp) > CmdPacketTxInfo.waitAckTimeout)
			{
				//ERR:超时
				FINGERVEIN_TASK_LOG("wait ack Time out cmd = %#2x,%#2x,%#2x,%#2x", CmdPacketTxInfo.cmd, currentTime, CmdPacketTxInfo.timeStamp, CmdPacketTxInfo.waitAckTimeout);
				if (pCmdCallback != NULL)
				{
					//各指令的对应reply的回调函数进行处理
					pCmdCallback(CmdPacketTxInfo.cmd, ret, NULL, 0);
					pCmdCallback = NULL;
				}
				CmdPacketTxInfo.status = TX_STA_IDLE;
			}
		}
	}
}

/**
  * @brief  接收数据并解析处理
  *
  * @note   先接收数据再解析数据
  */
static void Fingervein_RxProcess(void)
{
	uint8_t *pData = NULL;
	pData = Fingervein_GetOnePacket(); //得到一包数据并检验校验和
	
    if (pData != NULL)
	{
		err_process(0);
		Fingervein_ParseRxPacket(pData); //解析数据
	}

	Fingervein_ResendCmdPacket();		 //超时重发命令包
}


/**
  * @brief  指静脉模块 数据打包
  * @note   
  *
  * @param  cmd：消息id
  * @param  pData：数据
  * @param  dataLen：数据长度
  * @param  waitAckFlag：等待回复标志
  * @return 成功返回SUCCESS，失败返回ERROR
  */
static ErrorStatus Fingervein_SendPacket(uint8_t packType, uint8_t cmd, uint8_t *pData, uint16_t dataLen, FlagStatus waitAckFlag)
{
	uint16_t calcSum = 0;
	CmdPacket_stu_t *pCmdPacket = (CmdPacket_stu_t *)CmdPacketTxInfo.dataBuf;
	ErrorStatus ret;

	CmdPacketTxInfo.cmd = cmd;
	CmdPacketTxInfo.waitAckFlag = waitAckFlag;
	CmdPacketTxInfo.sendCnt = 1;
	CmdPacketTxInfo.status = TX_STA_WAIT_ACK;
	CmdPacketTxInfo.timeStamp = OSAL_GetTickCount();

	pCmdPacket->head.stx = PROTOCOL_STX;
	pCmdPacket->head.stx = SWAP16(pCmdPacket->head.stx); //大小端转化
	pCmdPacket->head.chipAddr = CHIPADDR;
	pCmdPacket->head.msgType = packType;
	pCmdPacket->head.dataLen = dataLen + 2;	    //原始data长度 + 最后2位检验和的长度
	pCmdPacket->head.dataLen = SWAP16(pCmdPacket->head.dataLen); //大小端转化
	memcpy(pCmdPacket->data, pData, dataLen);

	calcSum = Fingervein_CalcCheckSum((uint8_t *)&(pCmdPacket->head.stx) + CHECK_SUM_DATA_START, dataLen + 2 + CHECK_SUN_LEN_ADD);
	// FINGERVEIN_TASK_LOG("calcSum = %d", calcSum);
	pCmdPacket->data[dataLen] = (calcSum >> 8);
	pCmdPacket->data[dataLen + 1] = (calcSum & 0X00FF);
	CmdPacketTxInfo.dataLen = sizeof(CmdPacket_stu_t) + dataLen + 2;

	//发送数据
    ret = Fingervein_LoadingDataToBeSent(CmdPacketTxInfo.dataBuf, CmdPacketTxInfo.dataLen | 0x8000);

	return ret;

}

/**
  * @brief 处理指静脉串口发送数据
  *
  * @note  
  */
static void Fingervein_TxProcess(void)
{
	FlagStatus ackFlag;
	FingerveinTxCmdMsg_stu_t TxData = {0};

	if (OSAL_RingBufferGetValidSize(operate_rbHandle) != 0)			//优先处理发送握手指令
	{
		if (CmdPacketTxInfo.status == TX_STA_IDLE)	// 发送状态空闲
		{
			if (OSAL_RingBufferRead(operate_rbHandle, &TxData) == SUCCESS)
			{
				if (TxData.cb != NULL)
				{
					ackFlag = SET;
					//指令对应回复的回调进行赋值
					pCmdCallback = TxData.cb;
					CmdPacketTxInfo.waitAckTimeout = TxData.timeout;
				}
				else
				{
					ackFlag = RESET;
				}
				Fingervein_SendPacket(PACK_TYPE_CMD, TxData.cmd, TxData.dataBuf, TxData.dataLen, ackFlag);
			}
		}
	}
	else if (OSAL_RingBufferGetValidSize(fingerveinTx_rbHandle) != 0)
	{
		if ((CmdPacketTxInfo.status == TX_STA_IDLE) && (module_Ready_Flag == SET))	// 发送状态空闲且已与模组握手成功
		{
			if (OSAL_RingBufferRead(fingerveinTx_rbHandle, &TxData) == SUCCESS)
			{
				if (TxData.cb != NULL)
				{
					ackFlag = SET;
					//指令对应回复的回调进行赋值
					pCmdCallback = TxData.cb;
					CmdPacketTxInfo.waitAckTimeout = TxData.timeout;
				}
				else
				{
					ackFlag = RESET;
				}
				Fingervein_SendPacket(PACK_TYPE_CMD, TxData.cmd, TxData.dataBuf, TxData.dataLen, ackFlag);
				// FINGERVEIN_TASK_LOG("RingBuff_Tx_OK cmd = %#X\r\n", TxData.cmd);
			}
		}
	}
}

/**
  * @brief  指静脉上电后的同步握手
  * @note   
  * @return 
  */
static void Fingervein_Sync_With_Module(void)
{
	//指静脉模块上电后，一定时间内未收到指静脉模块的上报的0x55握手信号；
	if (module_Ready_Flag == RESET)		
	{
		/*MCU主动向模块发送握手信号*/
		Fingervein_Cmd_Hello();
	}
}


/**
  * @brief  指静脉组件初始化
  * @note   
  * @return 
  */
static void Fingervein_Init(void)
{
	if (fingervein_Init_Flag == RESET)
	{
		InputPort_stu_t button_list[] = 
		{
			{"FINGERVEIN_INT", IRQ_VHW_FINGERVEIN, INPUT_PORT_LOGIC_HIGH, INPUT_PORT_FUNC_SINGLE}, //中断脚
		};
		/* 注册端口 */
		InputPort_Registered(button_list, OSAL_LENGTH(button_list), Fingervein_Int_Irq_Handler);
		InputPort_EnableProt("FINGERVEIN_INT");

		/* 创建环形缓存 */
		Fingervein_CreateRingBuffHandle();

		fingervein_Init_Flag = SET;
	}

	/* 注册指静脉串口回调函数 */
	Device_RegisteredCB(VHW_UART_FINGERVEIN, Fingervein_ReceiveCb);
	// 使能指静脉的串口
	Device_Enable(VHW_UART_FINGERVEIN);

	/* 指静脉协议初始化 */
	Fingervein_ProtocolInit();

}



/**
  * @brief  指静脉组件中断事件处理
  * @note        
  */
static void Fingervein_Isr_Event_Handle(void)
{
	FINGERVEIN_TASK_LOG("Fingervein_Isr_Event_Handle\r\n");

	if (fingervein_Status_Data.mode == WORK_MODE_DISABLE)
	{
		return;
	}
	else if (fingervein_Status_Data.mode == WORK_MODE_ADD)
	{
		if (!process_Start_Flag)	//指静脉注册流程未开始
		{
			//录入模式下，touch_out信号触发，直接开始注册发送注册指令，先不判断touch状态
			process_Start_Flag = SET;
			fingervein_Status = FVN_STATUS_INIT;										//指静脉流程切换到初始化状态；
			OSAL_EventRepeatCreate(COMP_FINGERVEIN, EVENT_FINGERVEIN_PROCESS, FINGERVEIN_PROCESSOR_TIME, EVT_PRIORITY_MEDIUM);
		}
	}
	else if (fingervein_Status_Data.mode == WORK_MODE_VERIFY)
	{
		OSAL_EventDelete(COMP_FINGERVEIN, EVENT_GET_TOUCH_STATUS);	

		// 指静脉中断触发，开始获取当前的指静脉的touch_status,单端接触还是双端接触；
		if (process_Start_Flag == RESET && getTouchStatus_Start_Flag == RESET)
		{
			getTouchStatus_Start_Flag = SET;
			getTouchStatus_Count = 0;
			// 创建一个单次事件去延时获取指静脉touch状态，防止手指刚放上去抖动，状态不稳，还没有同时接触两端的触点；
			OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_GET_TOUCH_STATUS, 50, EVT_PRIORITY_MEDIUM);
		}
	}
	
	return;
}


/**
  * @brief 指静脉流程处理
  * @note
  * @param
  * @return
  */
static void Fingervein_Processor(void)
{
	FingerveinMsg_t fingerveinMsg;

	if (enroll_Abort_Flag == SET)													//按了*号键切换菜单，中断注册流程标志为真
	{
		FINGERVEIN_TASK_LOG("Fingervein_Processor abort\r\n");
		enroll_Abort_Flag = RESET;
		fingervein_Status = FVN_STATUS_END;                  						//切换到结束
	}	

	switch (fingervein_Status)
	{
		case FVN_STATUS_INIT:       	/* 初始化 */
		{
			if (fingervein_Status_Data.mode == WORK_MODE_ADD)
			{
				if (template_Save_Num == 0xFF)			//应用层添加指静脉时候，下发的编号为0xFF时，表示map已满，没有可用的id了
				{
					fingerveinMsg.action = FINGERVEIN_ACTION_VERIFY_GET_IMAGE_OK;
					fingerveinMsg.fingerveinNumber = 0xFF;
					OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  	//上报应用层去播报“嘟”一声，打断上一条语音；

					fingerveinMsg.action = FINGERVEIN_ACTION_ADD_ERR;				//上报应用层指静脉录入失败
            		fingerveinMsg.fingerveinNumber = 0xFF;
            		OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

					process_Start_Flag = RESET;										//录入注册过程，提前将start_flag清零，告诉录入结束返回上一级菜单要切换指静脉模式是正常录入结束，非人为终止；
					fingervein_Status = FVN_STATUS_END;                  			//切换到结束
				}
				else
				{
					FINGERVEIN_TASK_LOG("Fingervein_Processor AutoEnroll start!\r\n");
					OSAL_SetTaskStatus(TASK_STA_ACTIVE); 								//指静脉注册流程开始：禁止系统休眠
					fingervein_Status_Data.enroll_num = 0;

					//发送自动注册命令
					Fingervein_Cmd_AutoEnroll();

					//创建一个单次事件，延时一段时间后去判断手指是否已正确放置
					#if defined(BOARD_M30J0_ADD_FINGERVEIN_WITH_FPT)
					OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_CHECK_FINGER_STATUS, 8000, EVT_PRIORITY_MEDIUM);	//KDS的K8603项目，延长检测手指状态的时间间隔；
					#else
					OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_CHECK_FINGER_STATUS, 1200, EVT_PRIORITY_MEDIUM);
					#endif

					fingervein_Status = FVN_STATUS_WAIT_ACK;							//切换到等待模组ACK回复
				}
			}
			else if (fingervein_Status_Data.mode == WORK_MODE_VERIFY)
			{
				FINGERVEIN_TASK_LOG("Fingervein_Processor AutoVerify start!\r\n");
				OSAL_SetTaskStatus(TASK_STA_ACTIVE); 								//指静脉流程开始：禁止系统休眠

				// 发送自动注册命令
				Fingervein_Cmd_AutoVerify();

				fingervein_Status = FVN_STATUS_WAIT_ACK;							//切换到等待模组ACK回复
			}
			else if (fingervein_Status_Data.mode == WORK_MODE_DISABLE)
            {
                fingervein_Status = FVN_STATUS_END;                  				//切换到结束
            }
		}
		break;

		case FVN_STATUS_WAIT_ACK:													//等待模组ACK回复
		{
			//空状态，不处理内容，
		}
		break;
		
		case FVN_STATUS_ENROLL_GET_IMAGE_TIME_UP:          /* 自动注册单次采图定时器时间到达，提醒手指拿开，采图结果等手指拿开才上报 */
		{
			//自动注册单次采图定时时间到达
			FINGERVEIN_TASK_LOG("Enroll:FVN_STATUS_ENROLL_GET_IMAGE_TIME_UP\r\n");
			if (fingervein_Status_Data.enroll_num == AUTO_ENROLL_MAX_NUMS - 1)		//已经录入5次，第六次采图结束就不用播报“松开手指，继续录入”
			{
				fingerveinMsg.action = FINGERVEIN_ACTION_ENROLL_GET_IMAGE_OK;
				fingerveinMsg.fingerveinNumber = 0xF6;
				OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  //上报应用层指静脉结束单次采图
			}
			else if (fingervein_Status_Data.enroll_num < AUTO_ENROLL_MAX_NUMS - 1)
			{
				fingerveinMsg.action = FINGERVEIN_ACTION_ENROLL_GET_IMAGE_OK;
				fingerveinMsg.fingerveinNumber = 0xff;
				OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  //上报应用层指静脉结束单次采图
			}
			// 自动注册单次采图定时器时间到达，切换到等到手指移开的状态
		}

		case FVN_STATUS_WAIT_FINGER_AWAY_START:       /* 开始等待手指挪开 */
		{
			FINGERVEIN_TASK_LOG("Enroll:FVN_STATUS_WAIT_FINGER_AWAY_START\r\n");
			OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_WAIT_FINGER_AWAY, FINGERVEIN_ENROLL_WAIT_FINGER_AWAY_TIME, EVT_PRIORITY_MEDIUM);
			fingervein_Status = FVN_STATUS_WAIT_ACK;		//切换到等待模组ACK回复
		}
		break;

		case FVN_STATUS_FINGER_AWAY:
		{
			fingervein_Status_Data.finger_out_count = 0;		//单次录入手指放置错误次数清零
			wait_Finger_Away_Count = 0;							//单次录入等待手指移开计数清零
			OSAL_EventDelete(COMP_FINGERVEIN, EVENT_WAIT_FINGER_AWAY);			//手指已拿开，删除“等待手指移开的事件”

			FINGERVEIN_TASK_LOG("Enroll:enroll_num = %d\r\n", fingervein_Status_Data.enroll_num);
			if (fingervein_Status_Data.enroll_num < AUTO_ENROLL_MAX_NUMS)
			{
				//指静脉单次录入完成后，创建一个单次事件，延时一段时间后去判断手指是否已正确放置
				OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_CHECK_FINGER_STATUS, 9000, EVT_PRIORITY_MEDIUM);

				fingerveinMsg.action = FINGERVEIN_ACTION_ENTER_AGAIN;
				fingerveinMsg.fingerveinNumber = 0xff;							//非打断方式播放
				OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  	//上报应用层拿开手指
			}

			fingervein_Status = FVN_STATUS_WAIT_ACK;						//切换到等待模组ACK回复
		}
		break;

		case FVN_STATUS_ENROLL_SUCCESS:
		{
			FINGERVEIN_TASK_LOG("FVN_STATUS_ENROLL_SUCCESS\r\n");
			fingerveinMsg.action = FINGERVEIN_ACTION_ADD_OK;				//上报应用层指静脉录入成功	
            fingerveinMsg.fingerveinNumber = template_Save_Num;
            OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

			process_Start_Flag = RESET;										//录入注册过程，提前将start_flag清零，告诉录入结束返回上一级菜单要切换指静脉模式是正常录入结束，非人为终止；
			fingervein_Status = FVN_STATUS_END;                  			//切换到结束

			fingervein_Status_Data.mode = WORK_MODE_DISABLE;				//指静脉录入完成后，将指静脉的工作模式设置成禁用，防止指静脉中断生效重新进入指静脉录入模式；
			template_Save_Num = 0xEE;										//恢复初始值
		}
		break;

		case FVN_STATUS_ENROLL_FAILED:
		{
			FINGERVEIN_TASK_LOG("FVN_STATUS_ENROLL_FAILED\r\n");
			fingerveinMsg.action = FINGERVEIN_ACTION_ADD_ERR;				//上报应用层指静脉录入失败
            fingerveinMsg.fingerveinNumber = 0xFF;
            OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

			process_Start_Flag = RESET;										//录入注册过程，提前将start_flag清零，告诉录入结束返回上一级菜单要切换指静脉模式是正常录入结束，非人为终止；
			fingervein_Status = FVN_STATUS_END;                  			//切换到结束

			fingervein_Status_Data.mode = WORK_MODE_DISABLE;				//指静脉录入完成后，将指静脉的工作模式设置成禁用，防止指静脉中断生效重新进入指静脉录入模式；
			template_Save_Num = 0xEE;										//恢复初始值
		}
		break;

		case FVN_STATUS_VERIFY_GET_IMAGE_OK:
		{
			//自动验证采图成功，上报应用层
			FINGERVEIN_TASK_LOG("AutoVerify:FVN_STATUS_VERIFY_GET_IMAGE_OK\r\n");
			fingerveinMsg.action = FINGERVEIN_ACTION_VERIFY_GET_IMAGE_OK;
			fingerveinMsg.fingerveinNumber = 0xFF;
			OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));  			//上报应用层指静脉图像获取成功

			fingervein_Status = FVN_STATUS_WAIT_ACK;								//切换到等待模组ACK回复
		}
		break;

		case FVN_STATUS_VERIFY_SUCCESS:
		{
			FINGERVEIN_TASK_LOG("FVN_STATUS_VERIFY_SUCCESS\r\n");
			fingerveinMsg.action = FINGERVEIN_ACTION_VERIFY_OK;						//上报应用层指静脉验证成功	
            fingerveinMsg.fingerveinNumber = template_Verify_Num;
            OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

			fingervein_Status = FVN_STATUS_WAIT_ACK;                  				//切换到等待模板更新回包状态
		}
		break;

		case FVN_STATUS_VERIFY_FAILED:
		{
			FINGERVEIN_TASK_LOG("FVN_STATUS_VERIFY_FAILED\r\n");
			fingerveinMsg.action = FINGERVEIN_ACTION_VERIFY_ERR;					//上报应用层指静脉验证失败
            fingerveinMsg.fingerveinNumber = 0xFF;
            OSAL_MessagePublish(&fingerveinMsg, sizeof(fingerveinMsg));

			fingervein_Status = FVN_STATUS_END;                  					//切换到结束状态
		}
		break;

		case FVN_STATUS_END:              /* 结束操作 */
		{
			FINGERVEIN_TASK_LOG("FVN_STATUS_END\r\n");
			/*删除事件*/
            OSAL_EventDelete(COMP_FINGERVEIN, EVENT_FINGERVEIN_PROCESS);
			OSAL_EventDelete(COMP_FINGERVEIN, EVENT_CHECK_FINGER_STATUS);			//删除“定时检测指静脉录入时手指是否正确放置事件”
			OSAL_EventDelete(COMP_FINGERVEIN, EVENT_WAIT_FINGER_AWAY);				//删除“等待手指移开的事件”
			OSAL_EventDelete(COMP_FINGERVEIN, EVENT_ENROLL_GET_IMAGE_TIMER);			//删除“指静脉单次录入时定时结束采图事件”
			/*标志和数值清零*/
			fingervein_Status_Data.enroll_num = 0;
			fingervein_Status_Data.finger_out_count = 0;
			wait_Finger_Away_Count = 0;
			finger_Touch_OK_Flag = RESET;
			process_Start_Flag = RESET;
            fingervein_Status = FVN_STATUS_INIT;
			CmdPacketTxInfo.status = TX_STA_IDLE;
            OSAL_SetTaskStatus(TASK_STA_NORMAL); //指静脉流程结束：允许系统休眠
			
		}
		break;

		default:
			break;
		
	}

}




bool Fingervein_Del_Num(uint8_t startNum, uint8_t nums)
{
	//删除指静脉模板时候，如果指静脉模块还没有上电，需要先上电；
	if (module_PowerOn_Flag == RESET)
	{
		FINGERVEIN_TASK_LOG("Fingervein module deltemplate power on\r\n");
		FINGERVEIN_MODULE_POWER_ON;
		module_PowerOn_Flag = SET;
	}

	if ((startNum == 0) && (nums == 100))
	{
		/* 删除0-100，清空指静脉模板库 */
		Fingervein_Cmd_DelAllTemplate();
	}
	else
	{
		/* 删除指定用户 */
		Fingervein_Cmd_DelTemplate(startNum, nums);
	}	
}


static void Fingervein_ProcessMbox(uint8_t *msg)
{
	FINGERVEIN_TASK_LOG("Fingervein_ProcessMbox: msg[0] = %d\r\n",msg[0]);
    switch (msg[0])
    {
		case FINGERVEIN_SETWORKMODE:		//切换指静脉任务工作模式
		{
			uint8_t mode = msg[1];
            fingerveinModeBuff = mode;
			template_Save_Num = msg[2];         
			
			if (mode != fingervein_Status_Data.mode)
			{
				if (fingervein_Status_Data.mode == FINGERVEIN_WORK_MODE_ADD)	
				{
					if (process_Start_Flag == SET)	//如果当前指静脉模式为添加模式，注册流程未完成，按了*号键返回上一层，就要终止当前的注册流程
					{
						// 发送取消指令
						CmdPacketTxInfo.status = TX_STA_IDLE;
						Fingervein_Cmd_Abort();

						// 注册中断标志置为真
						enroll_Abort_Flag = SET;
					}
				}

				fingervein_Status_Data.mode = (WorkMode_enum_t)mode;
				if (fingervein_Status_Data.mode == FINGERVEIN_WORK_MODE_ADD)
				{
					FINGERVEIN_TASK_LOG("fingervein switch add mode, fvn_num = %d\r\n",template_Save_Num);
				}
				else if (fingervein_Status_Data.mode == FINGERVEIN_WORK_MODE_VERIFY)
				{
					FINGERVEIN_TASK_LOG("fingervein switch verify mode\r\n");
				}
				else if (fingervein_Status_Data.mode == FINGERVEIN_WORK_MODE_DISABLE)
				{
					FINGERVEIN_TASK_LOG("fingervein switch disable mode\r\n");
				}
			}
			FINGERVEIN_TASK_LOG("fingervein_Workmode = %d\r\n", fingervein_Status_Data.mode);  
		}
		break;

		case FINGERVEIN_DELETEIMAGE:		//删除指静脉图像
		{
			uint8_t startNum, nums;
			startNum = msg[1];
			nums = msg[2];
			FINGERVEIN_TASK_LOG("Users_DeleteFingerveinImage: startNum = %d, nums = %d\r\n", startNum, nums);

			Fingervein_Del_Num(startNum, nums);
		}
		break;

		default:
			break;
    }
}


/**
  * @brief SYS_API,获取指静脉模组版本号
  * @note	
  * @param
  * @return	
  */
static ErrorStatus Fingervein_Read_Version(uint8_t *pData, uint8_t *pLen)
{
	uint8_t versionBuff[FINGERVEIN_VERSION_LEN] = {0};
	OSAL_NvRead(OSAL_OFFSET(NvFingervein_stu_t, fingerveinVersion), versionBuff, FINGERVEIN_VERSION_LEN);
	for (uint8_t i = 1; i < FINGERVEIN_VERSION_LEN; i++)
	{
		if (!((versionBuff[i] >= '0' && versionBuff[i] <= '9') || versionBuff[i] == '.'))		//对从NV区域里面读取版本号进行数据合理性检验
		{
			*pLen = 0;
			return ERROR;
		}
	}
	memcpy(pData, versionBuff, FINGERVEIN_VERSION_LEN);
	*pLen = FINGERVEIN_VERSION_LEN;

	return SUCCESS;
}


/**
  * @brief SYS_API,进入指静脉产测整机测试
  * @note	
  * @param
  * @return	
  */
static ErrorStatus Fingervein_Start_Ate_Test(void)
{
	FINGERVEIN_TASK_LOG("Fingervein:Start Ate Test\r\n");
	fingervein_Status_Data.mode = WORK_MODE_DISABLE;		//切换到禁用模式
	Fingervein_Cmd_AteTest();

	return SUCCESS;
}


/**
  * @brief  Fingervein_Task指静脉任务函数
  *
  * @note   1.任务函数内不能写阻塞代码
  *         2.任务函数每次运行只处理一个事件
  *         3.任务函数必须添加到osal_config.h文件里面
  *
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Fingervein_Task(uint32_t event)
{
	if (event & EVENT_SYS_START) //任务启动
	{
		FINGERVEIN_TASK_LOG("Fingervein task start\r\n");
		/* 指静脉组件初始化*/
		Fingervein_Init();

		SYS_API(Fingervein_Start_Ate_Test);

		/* 创建定时处理指静脉协议事件 */
   		OSAL_EventRepeatCreate(COMP_FINGERVEIN, EVENT_FINGERVEIN_PROTOCOL, 10, EVT_PRIORITY_MEDIUM);

		//Task首次上电启动时会同步给指静脉模块上电，读取指静脉模块的版本号，并保存到NV；
		if (fisrt_PowerOn_Flag == RESET)
		{
			//给模组上电
			FINGERVEIN_TASK_LOG("Fingervein module first power on\r\n");
			FINGERVEIN_MODULE_POWER_ON;
			module_PowerOn_Flag = SET;
			/* 创建指静脉模块定时同步握手事件 */
			OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_SYNC_WITH_MODULE, FINGERVEIN_MODULE_BOOT_TIME, EVT_PRIORITY_MEDIUM);
			/* 读取指静脉模块版本号 */ 
			Fingervein_Cmd_GetVersion();

			fisrt_PowerOn_Flag = SET;
		}

		if (fingervein_wake_flag == 1)         // 指静脉中断唤醒系统，
        {
            fingervein_wake_flag = 0;
			FINGERVEIN_TASK_LOG("Fingervein module wakeup power on\r\n");
			//给模组上电
			FINGERVEIN_MODULE_POWER_ON;
			module_PowerOn_Flag = SET;
			/* 创建指静脉模块定时同步握手事件 */
			OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_SYNC_WITH_MODULE, FINGERVEIN_MODULE_BOOT_TIME, EVT_PRIORITY_MEDIUM);
        }

		/* 注册对外开放的API接口,*/
		SYS_API(Fingervein_Read_Version);

		return (event ^ EVENT_SYS_START);
	}

	/* 系统中断事件 */
    if (event & EVENT_SYS_ISR)
    {
		//检测到指静脉touch中断输入，先给模组上电；
		if (module_PowerOn_Flag == RESET)
		{
			FINGERVEIN_TASK_LOG("Fingervein module ISR power on\r\n");
			FINGERVEIN_MODULE_POWER_ON;
			module_PowerOn_Flag = SET;
			/* 创建指静脉模块定时同步握手事件 */
			OSAL_EventSingleCreate(COMP_FINGERVEIN, EVENT_SYNC_WITH_MODULE, FINGERVEIN_MODULE_BOOT_TIME, EVT_PRIORITY_MEDIUM);
		}

        Fingervein_Isr_Event_Handle();
        return ( event ^ EVENT_SYS_ISR );
    }

	/* 指静脉录入和验证流程处理事件 */
	if (event & EVENT_FINGERVEIN_PROCESS)
	{
		Fingervein_Processor();
        return ( event ^ EVENT_FINGERVEIN_PROCESS );
    }

	/* 指静脉串口协议事件 */
	if (event & EVENT_FINGERVEIN_PROTOCOL)
	{
		/* 指静脉串口接收数据处理 */
		Fingervein_RxProcess();

		/* 指静脉串口发送数据处理 */
		Fingervein_TxProcess();
		return (event ^ EVENT_FINGERVEIN_PROTOCOL);
	}

	if (event & EVENT_SYS_MBOX)
    {
        uint8_t buffer[50] = {0};
        while (OSAL_MboxAccept(buffer))
        {
            Fingervein_ProcessMbox(buffer);
        }
        return ( event ^ EVENT_SYS_MBOX );
    }

	/*指静脉模块上电后，进行同步握手的事件*/
    if (event & EVENT_SYNC_WITH_MODULE)
    {
		Fingervein_Sync_With_Module();
        return ( event ^ EVENT_SYNC_WITH_MODULE );
    }

	/*指静脉验证时，获取指静脉Touch状态事件*/
    if (event & EVENT_GET_TOUCH_STATUS)
    {
		Fingervein_Cmd_GetTouchStatus();
        return ( event ^ EVENT_GET_TOUCH_STATUS );
    }

	/*指静脉录入时，定时检测手指是否正确放置事件*/
    if (event & EVENT_CHECK_FINGER_STATUS)
    {
		Fingervein_Get_FingerStatus();
        return ( event ^ EVENT_CHECK_FINGER_STATUS );
    }

	/*指静脉单次录入时，定时采图完成事件*/
    if (event & EVENT_ENROLL_GET_IMAGE_TIMER)
    {
		fingervein_Status = FVN_STATUS_ENROLL_GET_IMAGE_TIME_UP;	//指静脉处理流程切换到单次采图时间到达；
		Enroll_Get_Image_Timer_On_Flag = RESET;						//定时采图定时器开始标志清零，
        return ( event ^ EVENT_ENROLL_GET_IMAGE_TIMER );
    }

	/*指静脉单次录入时,采图结束，开始等待手指移开*/
    if (event & EVENT_WAIT_FINGER_AWAY)
    {
		Fingervein_Wait_Finger_Away();
        return ( event ^ EVENT_WAIT_FINGER_AWAY );
    }

	/* 休眠处理 */
	if (event & EVENT_SYS_SLEEP)
	{
    	/* 清空指静脉发送和设置缓存数据 */
		Fingervein_ResetRingBuffData();
		/*删除事件*/
		OSAL_EventDelete(COMP_FINGERVEIN, EVENT_FINGERVEIN_PROTOCOL);
		OSAL_EventDelete(COMP_FINGERVEIN, EVENT_FINGERVEIN_PROCESS);
		OSAL_EventDelete(COMP_FINGERVEIN, EVENT_CHECK_FINGER_STATUS);			//删除“定时检测指静脉录入时手指是否正确放置事件”
		OSAL_EventDelete(COMP_FINGERVEIN, EVENT_WAIT_FINGER_AWAY);				//删除“等待手指移开的事件”
		OSAL_EventDelete(COMP_FINGERVEIN, EVENT_ENROLL_GET_IMAGE_TIMER);			//删除“指静脉单次录入时定时结束采图事件”
		OSAL_EventDelete(COMP_FINGERVEIN, EVENT_GET_TOUCH_STATUS);
		/*标志和数值清零*/
		fingervein_Status_Data.enroll_num = 0;
		fingervein_Status_Data.finger_out_count = 0;
		wait_Finger_Away_Count = 0;
		finger_Touch_OK_Flag = RESET;
		process_Start_Flag = RESET;
		fingervein_Status = FVN_STATUS_INIT;
		CmdPacketTxInfo.status = TX_STA_IDLE;
		module_Ready_Flag = RESET;
		getTouchStatus_Start_Flag = RESET;
    	/* 关闭指静脉串口 */
		Device_Disable(VHW_UART_FINGERVEIN);
    	/* 关闭指静脉电源 */
		FINGERVEIN_MODULE_POWER_OFF;
		module_PowerOn_Flag = RESET;

		return (event ^ EVENT_SYS_SLEEP);
	}


	return 0;
}
COMPONENT_TASK_EXPORT(COMP_FINGERVEIN, Fingervein_Task, FINGERVEIN_NV_SIZE);


/**
  * @brief  指静脉唤醒逻辑处理
  * @param  
  * @return 
  */
static int32_t Fingervein_WakeHandle(uint32_t dev)
{
    fingervein_wake_flag = 1;
    return 1; 
}
COMPONENT_WAKEUP_EXPORT(COMP_FINGERVEIN, Fingervein_WakeHandle, IRQ_VHW_FINGERVEIN);